package org.raymond.iworks.admin.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.raymond.iworks.admin.service.ITSysRoleService;
import org.raymond.iworks.apis.common.ErrorCode;
import org.raymond.iworks.apis.exception.BaseException;
import org.raymond.iworks.apis.vo.role.RoleCreateVO;
import org.raymond.iworks.apis.vo.role.RoleDelVO;
import org.raymond.iworks.apis.vo.role.RoleInfoVO;
import org.raymond.iworks.apis.vo.role.RoleUpdateVO;
import org.raymond.iworks.repository.entity.TRolePermissionRel;
import org.raymond.iworks.repository.entity.TSysRole;
import org.raymond.iworks.repository.entity.TUserRoleRel;
import org.raymond.iworks.repository.entity.enums.StateEnum;
import org.raymond.iworks.repository.repository.TRolePermissionRelRepository;
import org.raymond.iworks.repository.repository.TSysRoleRepository;
import org.raymond.iworks.repository.repository.TUserRoleRelRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author raymond
 * @version V1.0
 */
@Slf4j
@Service
public class TSysRoleServiceImpl implements ITSysRoleService {
    private TSysRoleRepository tSysRoleRepository;
    @Autowired
    private TRolePermissionRelRepository tRolePermissionRelRepository;
    @Autowired
    private TUserRoleRelRepository tUserRoleRelRepository;

    @Override
    public List<TSysRole> getsChildRole(Set<Long> roleIdSet) {
        if(CollectionUtils.isEmpty(roleIdSet)){
            return null;
        }
        List<TSysRole> roleList = tSysRoleRepository.findAllById(roleIdSet);
        Set<Long> childRoleIdSet = roleList.stream()
                .filter(e->e.equals(StateEnum.NORMAL.getCode()))
                .mapToLong(TSysRole::getId)
                .boxed()
                .collect(Collectors.toSet());
        List<TSysRole> childRoleList = getsChildRole(childRoleIdSet);
        if(CollectionUtils.isNotEmpty(childRoleList)){
            roleList.addAll(childRoleList);
        }
        return roleList;
    }

    @Override
    public List<TSysRole> getsAssociatedRoleByUserId(Long userId) {
        if(userId==null) {
            return null;
        }

        List<TUserRoleRel> userRoleRels = tUserRoleRelRepository.findAllById(List.of(userId));
        if(CollectionUtils.isEmpty(userRoleRels)) {
            return null;
        }
        Set<Long> directRoleIdSet = userRoleRels.stream().mapToLong(TUserRoleRel::getRoleId).boxed().collect(Collectors.toSet());
        List<TSysRole> directRoleList = tSysRoleRepository.findAllById(directRoleIdSet);
        if(CollectionUtils.isEmpty(directRoleList)) {
            return null;
        }
        directRoleIdSet = directRoleList.stream()
                .filter(e->e.equals(StateEnum.NORMAL.getCode()))
                .mapToLong(TSysRole::getId)
                .boxed()
                .collect(Collectors.toSet());
        List<TSysRole> childRoleList = getsChildRole(directRoleIdSet);
        List<TSysRole> allRelRoleList = Lists.newArrayList();
        allRelRoleList.addAll(directRoleList);
        allRelRoleList.addAll(childRoleList);
        return allRelRoleList;
    }

    @Override
    public boolean save(RoleCreateVO vo) {
        TSysRole target = TSysRole.builder().name(vo.getName()).build();
        tSysRoleRepository.save(target);

        Long roleId = target.getId();
        List<Long> permissions = vo.getPermissions();
        if(CollectionUtils.isNotEmpty(permissions)){
            List<TRolePermissionRel> entities = permissions.stream().map(i->TRolePermissionRel.builder().roleId(roleId).permissionId(i).build()).collect(Collectors.toList());
            tRolePermissionRelRepository.saveAll(entities);
        }
        return true;
    }

    @Override
    public boolean update(RoleUpdateVO vo) {
        TSysRole target = TSysRole.builder().build();
        BeanUtils.copyProperties(vo, target);

        Long roleId = vo.getId();
        List<Long> permissions = vo.getPermissions();
        if(CollectionUtils.isEmpty(permissions)){
            TRolePermissionRel removed = TRolePermissionRel.builder().roleId(roleId).build();
            tRolePermissionRelRepository.delete(removed);
        }else{
            TRolePermissionRel filtered = TRolePermissionRel.builder().roleId(roleId).build();
            List<TRolePermissionRel> existList = tRolePermissionRelRepository.findAll(Example.of(filtered));
            List<Long> exists = existList.stream().map(TRolePermissionRel::getPermissionId).toList();
            List<Long> needInsert = permissions.stream().filter(e->!exists.contains(e)).collect(Collectors.toList());
            List<Long> needRemove = exists.stream().filter(e->!permissions.contains(e)).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(needInsert)){
                List<TRolePermissionRel> entities = needInsert.stream().map(i->TRolePermissionRel.builder().roleId(roleId).permissionId(i).build()).collect(Collectors.toList());
                tRolePermissionRelRepository.saveAll(entities);
            }
            if(CollectionUtils.isNotEmpty(needRemove)){
                List<TRolePermissionRel> removeList = needRemove.stream().map(r->{
                    TRolePermissionRel rp = TRolePermissionRel.builder().build();
                    rp.setRoleId(roleId);
                    rp.setPermissionId(r);
                    return rp;
                }).toList();
                tRolePermissionRelRepository.deleteAll(removeList);
            }
        }

        tSysRoleRepository.save(target);
        return true;
    }

    @Override
    public boolean removeById(RoleDelVO vo) {
        Long roleId = vo.getId();
        TSysRole tSysRole = tSysRoleRepository.getReferenceById(roleId);
        if(tSysRole==null){
            throw new BaseException(ErrorCode.NOT_FOUND, "角色不存在");
        }

        TRolePermissionRel removed = TRolePermissionRel.builder().roleId(roleId).build();
        tRolePermissionRelRepository.delete(removed);
        return true;
    }

    @Override
    public RoleInfoVO getById(Long id) {
        TSysRole tSysRole = tSysRoleRepository.getReferenceById(id);
        if(tSysRole==null){
            throw new BaseException(ErrorCode.NOT_FOUND, "角色不存在");
        }
        RoleInfoVO vo = new RoleInfoVO();
        BeanUtils.copyProperties(tSysRole, vo);

        TRolePermissionRel removed = TRolePermissionRel.builder().roleId(id).build();
        List<TRolePermissionRel> rpList = tRolePermissionRelRepository.findAll(Example.of(removed));
        if(CollectionUtils.isNotEmpty(rpList)){
            List<Long> permissions = rpList.stream().map(TRolePermissionRel::getPermissionId).collect(Collectors.toList());
            vo.setPermissions(permissions);
        }
        return vo;
    }
}
